home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / MNetsrc.hqx / Mac TCP_IP Source v.33 / ax_mbx.c < prev    next >
C/C++ Source or Header  |  1989-03-03  |  19KB  |  878 lines

  1. #include <stdio.h>
  2. #include <time.h>
  3. #include <ctype.h>
  4. #include "global.h"
  5. #ifdef MAC
  6. #include "config.h"
  7. #include <types.h>
  8. #endif
  9. #include "mbuf.h"
  10. #include "ax25.h"
  11. #include "timer.h"
  12. #include "iface.h"
  13. #include "lapb.h"
  14. #include "netrom.h"
  15. #include "nr4.h"
  16. #include "ax_mbx.h"
  17. #include "cmdparse.h"
  18.  
  19. /*
  20. #define MBDEBUG
  21. */
  22.  
  23. struct mbx *mbox[NUMMBX] ;
  24. int ax25mbox ;
  25.  
  26. #ifdef CALLBK
  27. static char mbbanner[] =
  28.     "[NET-$]\rWelcome to the %s TCP/IP Mailbox\r(C)hat, (I)nquire, (S)end, (B)ye >\r" ;
  29. static char mbmenu[] = "(C)hat, (I)nquire, (S)end, (B)ye >\r" ;
  30. #else
  31. static char mbbanner[] =
  32.     "[NET-$]\rWelcome to the %s TCP/IP Mailbox\r(C)hat, (S)end, (B)ye >\r" ;
  33. static char mbmenu[] = "(C)hat, (S)end, (B)ye >\r" ;
  34. #endif
  35.  
  36. dombox(argc, argv)
  37. int argc ;
  38. char *argv[] ;
  39. {
  40.     if (argc < 2) {
  41.         domboxdisplay() ;
  42.         return 0 ;
  43.     }
  44.  
  45.     if (argv[1][0] == 'y' || (strcmp(argv[1],"on") == 0))
  46.         ax25mbox = 1 ;
  47.     else if (argv[1][0] == 'n' || (strcmp(argv[1],"off") == 0))
  48.         ax25mbox = 0 ;
  49.     else if (argv[1][0] == '?')
  50.         printf("ax25 mailbox is %s\n", ax25mbox ? "on" : "off") ;
  51.     else
  52.         printf("usage: mbox [y|n|?]\n") ;
  53.  
  54.     return 0 ;
  55. }
  56.  
  57. static domboxdisplay()
  58. {
  59.     int i ;
  60.     struct mbx *m ;
  61.     static char *states[] = {"NONE","CMD","SUBJ","DATA"} ;
  62.     static char *mbtype[] = {"NONE","AX25 ","NET/ROM"} ;
  63.     
  64.     printf(" User     State    Type    &cb\n") ;
  65.  
  66.     for (i = 0 ; i < NUMMBX ; i++)
  67.         if ((m = mbox[i]) != NULLMBX)
  68.             printf("%-10s %-4s  %-7s  ", m->name, states[m->state],
  69.                     mbtype[m->type]);
  70.                     if (m->type == MBX_AX25)
  71.                         printf("%04x\n",m->cb.ax25_cb);
  72.                     else
  73.                         printf("%04x\n",m->cb.nr4_cb);
  74. }
  75.  
  76.     
  77. static struct mbx *
  78. newmbx()
  79. {
  80.     int i ;
  81.     struct mbx *m ;
  82.  
  83.     for (i = 0 ; i < NUMMBX ; i++)
  84.         if (mbox[i] == NULLMBX) {
  85.             if ((m = mbox[i] = (struct mbx *)calloc(1,sizeof(struct mbx)))
  86.                 == NULLMBX)
  87.                 return NULLMBX ;
  88.             m->mbnum = i ;
  89.             return m ;
  90.         }
  91.  
  92.     /* If we get here, there are no free mailbox sessions */
  93.  
  94.     return NULLMBX ;
  95. }
  96.  
  97.  
  98. /* Incoming mailbox session via ax.25 */
  99.  
  100. void
  101. mbx_incom(axp,cnt)
  102. register struct ax25_cb *axp ;
  103. int16 cnt ;
  104. {
  105.     struct mbx *m ;
  106.     struct mbuf *bp, *recv_ax25() ;
  107.     char *cp ;
  108.     extern char hostname[] ;
  109.     void mbx_rx(), mbx_state() ;
  110.     extern char *index() ;
  111.     
  112.     if ((m = newmbx()) == NULLMBX) {
  113.         disc_ax25(axp) ;    /* no memory! */
  114.         return ;
  115.     }
  116.  
  117.     m->state = MBX_CMD ;    /* start in command state */
  118.     m->type = MBX_AX25 ;    /* this is an ax.25 mailbox session */
  119.     m->cb.ax25_cb = axp ;
  120.  
  121.     pax25(m->name,&axp->addr.dest) ;
  122.     cp = index(m->name,'-') ;
  123.     if (cp != NULLCHAR)            /* get rid of SSID */
  124.         *cp = '\0' ;
  125.  
  126.     m->lp = m->line ;        /* point line pointer at buffer */
  127.     axp->r_upcall = mbx_rx ;
  128.     axp->s_upcall = mbx_state ;
  129.     axp->user = (char *)m ;
  130.  
  131.     /* The following is necessary because we didn't know we had a */
  132.     /* "real" ax25 connection until a data packet came in.  We    */
  133.     /* can't be spitting banners out at every station who connects, */
  134.     /* since they might be a net/rom or IP station.  Sorry.  */
  135.     
  136.     bp = recv_ax25(axp,cnt) ;        /* get the initial input */
  137.     free_p(bp) ;                    /* and throw it away to avoid confusion */
  138.  
  139.     /* Now say hi */
  140.     
  141.     if ((bp = alloc_mbuf(strlen(hostname) + strlen(mbbanner) + 2)) == NULLBUF) {
  142.         disc_ax25(axp) ; /* mbx_state will fix stuff up */
  143.         return ;
  144.     }
  145.  
  146.     *bp->data = PID_FIRST | PID_LAST | PID_NO_L3 ;    /* pid */
  147.     (void)sprintf(bp->data+1,mbbanner,hostname) ;
  148.     bp->cnt = strlen(bp->data+1) + 1 ;
  149.  
  150.     send_ax25(axp,bp) ;                    /* send greeting message and menu */
  151. }
  152.  
  153. /* receive upcall for ax.25 */
  154. /* mbx_rx collects lines, and calls mbx_line when they are complete. */
  155. /* If the lines get too long, it arbitrarily breaks them. */
  156.  
  157. void mbx_rx(axp,cnt)
  158. struct ax25_cb *axp ;
  159. int16 cnt ;
  160. {
  161.     struct mbuf *bp, *recv_ax25() ;
  162.     struct mbx *m ;
  163.     char c ;
  164.     int mbx_line() ;
  165.     
  166.     m = (struct mbx *)axp->user ;
  167.     
  168.     if ((bp = recv_ax25(axp,cnt)) == NULLBUF)
  169.         return ;
  170.  
  171.     while (pullup(&bp,&c,1) == 1) {
  172.         if (c == '\r') {
  173.             *m->lp = '\0' ;            /* null terminate */
  174.             if (mbx_line(m) == -1) {    /* call the line processor */
  175.                 free_p(bp) ;        /* toss the rest */
  176.                 break ;                /* get out - we're obsolete */
  177.             }
  178.             m->lp = m->line ;        /* reset the pointer */
  179.         }
  180.         else if ((m->lp - m->line) == (MBXLINE - 1)) {
  181.             *m->lp++ = c ;
  182.             *m->lp = '\0' ;
  183.             if (mbx_line(m) == -1) {
  184.                 free_p(bp) ;
  185.                 break ;
  186.             }
  187.             m->lp = m->line ;
  188.         }
  189.         else
  190.             *m->lp++ = c ;
  191.     }
  192. }
  193.  
  194. /* state upcall for ax.25 */
  195.  
  196. void mbx_state(axp,old,new)
  197. struct ax25_cb *axp ;
  198. int old, new ;
  199. {
  200.     struct mbx *m ;
  201.     void free_mbx() ;
  202.     
  203.     m = (struct mbx *)axp->user ;
  204.  
  205.     /* dummy for now ... */
  206.     if (new == DISCONNECTED) {
  207.         axp->user = NULLCHAR ;
  208.         free_mbx(m) ;
  209.     }
  210. }
  211.  
  212.  
  213. /* Incoming mailbox session via net/rom */
  214.  
  215. void
  216. mbx_nr4incom(cb)
  217. register struct nr4cb *cb ;
  218. {
  219.     struct mbx *m ;
  220.     struct mbuf *bp ;
  221.     char *cp ;
  222.     extern char hostname[] ;
  223.     void mbx_nr4rx(), mbx_nr4state() ;
  224.     extern char *index() ;
  225.     
  226.     if ((m = newmbx()) == NULLMBX) {
  227.         disc_nr4(cb) ;    /* no memory! */
  228.         return ;
  229.     }
  230.  
  231.     m->state = MBX_CMD ;    /* start in command state */
  232.     m->type = MBX_NETROM ;    /* mailbox session type is net/rom */
  233.     m->cb.nr4_cb = cb ;
  234.  
  235.     pax25(m->name,&cb->user) ;
  236.     cp = index(m->name,'-') ;
  237.     if (cp != NULLCHAR)            /* get rid of SSID */
  238.         *cp = '\0' ;
  239.  
  240.     m->lp = m->line ;        /* point line pointer at buffer */
  241.     cb->r_upcall = mbx_nr4rx ;
  242.     cb->s_upcall = mbx_nr4state ;
  243.     cb->puser = (char *)m ;
  244.  
  245.     /* Say hi */
  246.     
  247.     if ((bp = alloc_mbuf(strlen(hostname) + strlen(mbbanner) + 1)) == NULLBUF) {
  248.         disc_nr4(cb) ; /* mbx_nr4state will fix stuff up */
  249.         return ;
  250.     }
  251.  
  252.     (void)sprintf(bp->data,mbbanner,hostname) ;
  253.     bp->cnt = strlen(bp->data) ;
  254.  
  255.     send_nr4(cb,bp) ;                    /* send greeting message and menu */
  256. }
  257.  
  258. /* receive upcall for net/rom */
  259. /* mbx_nr4rx collects lines, and calls mbx_line when they are complete. */
  260. /* If the lines get too long, it arbitrarily breaks them. */
  261.  
  262. void mbx_nr4rx(cb,cnt)
  263. struct nr4cb *cb ;
  264. int16 cnt ;
  265. {
  266.     struct mbuf *bp ;
  267.     struct mbx *m ;
  268.     char c ;
  269.     int mbx_line() ;
  270.     
  271.     m = (struct mbx *)cb->puser ;
  272.     
  273.     if ((bp = recv_nr4(cb,cnt)) == NULLBUF)
  274.         return ;
  275.  
  276.     while (pullup(&bp,&c,1) == 1) {
  277.         if (c == '\r') {
  278.             *m->lp = '\0' ;            /* null terminate */
  279.             if (mbx_line(m) == -1) {    /* call the line processor */
  280.                 free_p(bp) ;        /* toss the rest */
  281.                 break ;                /* get out - we're obsolete */
  282.             }
  283.             m->lp = m->line ;        /* reset the pointer */
  284.         }
  285.         else if ((m->lp - m->line) == (MBXLINE - 1)) {
  286.             *m->lp++ = c ;
  287.             *m->lp = '\0' ;
  288.             if (mbx_line(m) == -1) {
  289.                 free_p(bp) ;
  290.                 break ;
  291.             }
  292.             m->lp = m->line ;
  293.         }
  294.         else
  295.             *m->lp++ = c ;
  296.     }
  297. }
  298.  
  299. /* state upcall for net/rom */
  300.  
  301. void mbx_nr4state(cb,old,new)
  302. struct nr4cb *cb ;
  303. int old, new ;
  304. {
  305.     struct mbx *m ;
  306.     void free_mbx() ;
  307.     
  308.     m = (struct mbx *)cb->puser ;
  309.  
  310.     if (new == NR4STDISC) {
  311.         cb->puser = NULLCHAR ;
  312.         free_mbx(m) ;
  313.     }
  314. }
  315.  
  316. static void
  317. free_mbx(m)
  318. struct mbx *m ;
  319. {
  320.     if (m->to != NULLCHAR)
  321.         free(m->to) ;
  322.  
  323.  
  324.     if (m->tofrom != NULLCHAR)
  325.         free(m->tofrom) ;
  326.  
  327.     if (m->tomsgid != NULLCHAR)
  328.         free(m->tomsgid) ;
  329.         
  330.     if (m->tfile != NULLFILE)
  331.         fclose(m->tfile) ;
  332.  
  333.     mbox[m->mbnum] = NULLMBX ;
  334.     
  335.     free(m) ;
  336. }
  337.  
  338.  
  339. static 
  340. mbx_line(m)
  341. struct mbx *m ;
  342. {
  343.     void ax_session(), nr4_session() ;
  344.     char *host ;
  345.     extern char hostname[] ;
  346. #ifdef MAC
  347.     char fullfrom[256] ;
  348. #else
  349.     char fullfrom[50] ;
  350. #endif
  351. #ifdef CALLBK
  352.     extern char *index();
  353.     char *cp;
  354. #endif
  355.     
  356.     if (m->state == MBX_CMD) {
  357.         switch (tolower(m->line[0])) {
  358.             case 'b':    /* bye - bye */
  359.                 switch (m->type) {
  360.                   case MBX_AX25:
  361.                     disc_ax25(m->cb.ax25_cb) ;
  362.                     break ;
  363.                   case MBX_NETROM:
  364.                       disc_nr4(m->cb.nr4_cb) ;
  365.                     break ;
  366.                 }
  367.                 return -1 ;    /* tell line processor to quit */
  368.                 break ;
  369.             case 'c':    /* chat */
  370.                 switch (m->type) {
  371.                   case MBX_AX25:
  372.                     m->cb.ax25_cb->user = NULLCHAR ;
  373.                     ax_session(m->cb.ax25_cb,0) ;    /* make it a chat session */
  374.                     break ;
  375.                   case MBX_NETROM:
  376.                     m->cb.nr4_cb->puser = NULLCHAR ;
  377.                     nr4_session(m->cb.nr4_cb) ;
  378.                     break ;
  379.                 }
  380.                 free_mbx(m) ;
  381.                 return -1 ;
  382.                 break ;
  383. #ifdef CALLBK
  384.             case 'i':    /* inquire */
  385.                 if ((cp = rindex(m->line,' ')) != NULLCHAR) {
  386.                     cp++;
  387.                     mac_callbka(m,cp);
  388.                     mbx_msg(m,mbmenu);
  389.                     break;
  390.                 }
  391.                 else {
  392.                     mbx_msg(m,
  393.                         "I command syntax error - format is:\r") ;
  394.                     mbx_msg(m,
  395.                         "  Inquire [callsign]\r") ;
  396.                     break;
  397.                 }
  398. #endif
  399.             case 's': {
  400.                 int badsubj = 0 ;
  401.  
  402.                 /* Get S-command type (B,P,T, etc.) */
  403.                 
  404.                 if (m->line[1] == '\0')
  405.                     m->stype = ' ' ;
  406.                 else
  407.                     m->stype = toupper(m->line[1]) ;
  408.                     
  409.                 if (mbx_to(m) == -1) {
  410.                     if (m->mblforw)
  411.                         mbx_msg(m,"NO\r") ;
  412.                     else {
  413.                         mbx_msg(m,
  414.                             "S command syntax error - format is:\r") ;
  415.                         mbx_msg(m,
  416.                           "  S name [@ host] [< from_addr] [$bulletin_id]\r") ;
  417.                     }
  418.                     badsubj++ ;
  419.                 }
  420.                 else if (validate_address(m->to) == 0)     {
  421.                     if (m->mblforw)
  422.                         mbx_msg(m, "NO\r") ;
  423.                     else
  424.                         mbx_msg(m, "Bad user or host name\r") ;
  425.                     free(m->to) ;
  426.                     m->to = NULLCHAR ;
  427.                     if (m->tofrom) {
  428.                         free(m->tofrom) ;
  429.                         m->tofrom = NULLCHAR ;
  430.                     }
  431.                     if (m->tomsgid) {
  432.                         free(m->tomsgid) ;
  433.                         m->tomsgid = NULLCHAR ;
  434.                     }
  435.                     badsubj++ ;
  436.                 }
  437.  
  438.                 if (badsubj)
  439.                     mbx_msg(m, m->mblforw ? ">\r" : mbmenu) ;
  440.                 else {
  441.                     m->state = MBX_SUBJ ;
  442.                     mbx_msg(m,    m->mblforw ? "OK\r" : "Subject:\r") ;
  443.                 }
  444.                 break ;
  445.             }
  446.             case '[':    /* This is an MBL BBS - say "OK", not "Subject:" */
  447.                 if (m->line[strlen(m->line) - 1] == ']') {
  448.                     m->mblforw = 1 ;
  449.                     mbx_msg(m,">\r") ;
  450.                 }
  451.                 break ;
  452.             case 'f':
  453.                 if (m->line[1] == '>' && m->mblforw) {
  454.                     mbx_msg(m,">\r") ;
  455.                     break ;
  456.                 }
  457.                 /* Otherwise drop through to "huh?" */
  458.             default:
  459.                 mbx_msg(m,"Huh?\r") ;
  460.                 mbx_msg(m, m->mblforw ? ">\r" : mbmenu) ;
  461.         }
  462.     return 0 ;
  463.     }
  464.     else if (m->state == MBX_SUBJ) {
  465.         if (mbx_data(m) == -1) {
  466.             mbx_msg(m,"Can't create temp file for mail\r") ;
  467.             mbx_msg(m, m->mblforw ? ">\r" : mbmenu) ;
  468.             free(m->to) ;
  469.             m->to = NULLCHAR ;
  470.             if (m->tofrom) {
  471.                 free(m->tofrom) ;
  472.                 m->tofrom = NULLCHAR ;
  473.             }
  474.             if (m->tomsgid) {
  475.                 free(m->tomsgid) ;
  476.                 m->tomsgid = NULLCHAR ;
  477.             }
  478.             m->state = MBX_CMD ;
  479.             return 0 ;
  480.         }
  481.         m->state = MBX_DATA ;
  482.         if (m->mblforw == 0)
  483.             mbx_msg(m,
  484.               "Enter message.  Terminate with /EX or ^Z in first column:\r") ;
  485.         return 0 ;
  486.     }
  487.     else if (m->state == MBX_DATA) {
  488.         if (m->line[0] == 0x1a ||
  489.             strcmp(m->line, "/ex") == 0 ||
  490.             strcmp(m->line, "/EX") == 0) {
  491.             if ((host = index(m->to,'@')) == NULLCHAR)
  492.                 host = hostname ;        /* use our hostname */
  493.             else
  494.                 host++ ;                /* use the host part of address */
  495.  
  496.             /* make up full from name for work file */
  497.             (void)sprintf(fullfrom,"%s@%s",m->name,hostname) ;
  498.             
  499.             fseek(m->tfile,0L,0) ;        /* reset to beginning */
  500.             if (queuejob((void *)0,m->tfile,host,m->to,fullfrom) != 0)
  501.                 mbx_msg(m,
  502.                         "Couldn't queue message for delivery\r") ;
  503.  
  504.             free(m->to) ;
  505.             m->to = NULLCHAR ;
  506.             if (m->tofrom) {
  507.                 free(m->tofrom) ;
  508.                 m->tofrom = NULLCHAR ;
  509.             }
  510.             if (m->tomsgid) {
  511.                 free(m->tomsgid) ;
  512.                 m->tomsgid = NULLCHAR ;
  513.             }
  514.             fclose(m->tfile) ;
  515.             m->tfile = NULLFILE ;
  516.             m->state = MBX_CMD ;
  517.             mbx_msg(m, m->mblforw ? ">\r" : mbmenu) ;
  518.             return 0 ;
  519.         }
  520.         /* not done yet! */
  521.         fprintf(m->tfile,"%s\n",m->line) ;
  522.         return 0 ;
  523.     }
  524. }
  525.  
  526. #ifndef CALLBK
  527. static
  528. #endif
  529. mbx_msg(m,msg)
  530. struct mbx *m ;
  531. char msg[] ;
  532. {
  533.     int len ;
  534.     struct mbuf *bp ;
  535.     struct ax25_cb *axp ;
  536.     struct nr4cb *cb ;
  537.  
  538.     len = strlen(msg) ;
  539.  
  540.     switch (m->type) {
  541.       case MBX_AX25:
  542.         axp = m->cb.ax25_cb ;
  543.             
  544.         if ((bp = alloc_mbuf(len+1)) == NULLBUF) {
  545.             disc_ax25(axp) ;
  546.             return -1 ;
  547.         }
  548.  
  549.         bp->cnt = len + 1 ;
  550.     
  551.         *bp->data = PID_FIRST | PID_LAST | PID_NO_L3 ;
  552.     
  553.         memcpy(bp->data+1, msg, len) ;
  554.  
  555.         send_ax25(axp,bp) ;
  556.  
  557.         break ;
  558.  
  559.       case MBX_NETROM:
  560.         cb = m->cb.nr4_cb ;
  561.  
  562.         if ((bp = alloc_mbuf(len)) == NULLBUF) {
  563.             disc_nr4(cb) ;
  564.             return -1 ;
  565.         }
  566.  
  567.         bp->cnt = len ;
  568.  
  569.         memcpy(bp->data, msg, len) ;
  570.  
  571.         send_nr4(cb, bp) ;
  572.  
  573.         break ;
  574.     }
  575.     return 0 ;
  576. }
  577.  
  578.  
  579. /* States for send line parser state machine */
  580.  
  581. #define        SKIP_CMD        1
  582. #define        LOOK_FOR_USER    2
  583. #define        IN_USER            3
  584. #define        AFTER_USER        4
  585. #define        LOOK_FOR_HOST    5
  586. #define        IN_HOST            6
  587. #define        AFTER_HOST        7
  588. #define        LOOK_FOR_FROM    8
  589. #define        IN_FROM            9
  590. #define        AFTER_FROM        10
  591. #define        LOOK_FOR_MSGID    11
  592. #define        IN_MSGID        12
  593. #define        FINAL_STATE        13
  594. #define        ERROR_STATE        14
  595.  
  596. /* Prepare the addressee.  If the address is bad, return -1, otherwise
  597.  * return 0
  598.  */
  599. static
  600. mbx_to(m)
  601. struct mbx *m ;
  602. {
  603.     register char *cp, *cp1 ;
  604.     int state ;
  605.     char *user, *host, *from, *msgid ;
  606.     int userlen = 0, hostlen = 0, fromlen = 0, msgidlen = 0 ;
  607.     
  608.     cp = m->line ;
  609.  
  610.     for (state = SKIP_CMD ; state < FINAL_STATE ; cp++) {
  611. #ifdef MBDEBUG
  612.         printf("State is %d, char is %c\n", state, *cp) ;
  613. #endif
  614.         switch (state) {
  615.             case SKIP_CMD:
  616.                 if (*cp == '\0')
  617.                     state = ERROR_STATE ;        /* no user */
  618.                 else if (isspace(*cp))
  619.                     state = LOOK_FOR_USER ;
  620.                 break ;
  621.             case LOOK_FOR_USER:
  622.                 if (*cp == '\0' || *cp == '@' || *cp == '<' || *cp == '$')
  623.                     state = ERROR_STATE ;        /* no user */
  624.                 else if (!isspace(*cp)) {        /* found start of user */
  625.                     user = cp ;                    /* point at start */
  626.                     userlen++ ;                    /* start counting */
  627.                     state = IN_USER ;
  628.                 }
  629.                 break ;
  630.             case IN_USER:
  631.                 switch (*cp) {
  632.                     case '\0':                    /* found username only */
  633.                         state = FINAL_STATE ;
  634.                         break ;
  635.                     case '@':
  636.                         state = LOOK_FOR_HOST ;    /* hostname should follow */
  637.                         break ;
  638.                     case '<':
  639.                         state = LOOK_FOR_FROM ;    /* from name should follow */
  640.                         break ;
  641.                     case '$':
  642.                         state = LOOK_FOR_MSGID ; /* message id should follow */
  643.                         break ;
  644.                     default:
  645.                         if (isspace(*cp))
  646.                             state = AFTER_USER ;    /* white space */
  647.                         else
  648.                             userlen++ ;                /* part of username */
  649.                 }
  650.                 break ;
  651.             case AFTER_USER:
  652.                 switch (*cp) {
  653.                     case '\0':
  654.                         state = FINAL_STATE ;        /* found username only */
  655.                         break ;
  656.                     case '@':
  657.                         state = LOOK_FOR_HOST ;        /* hostname follows */
  658.                         break ;
  659.                     case '<':
  660.                         state = LOOK_FOR_FROM ;        /* fromname follows */
  661.                         break ;
  662.                     case '$':
  663.                         state = LOOK_FOR_MSGID ;    /* message id follows */
  664.                         break ;
  665.                     default:
  666.                         if (!isspace(*cp))
  667.                             state = ERROR_STATE ;
  668.                 }
  669.                 break ;
  670.             case LOOK_FOR_HOST:
  671.                 switch (*cp) {
  672.                     case '\0':                    /* user@? */
  673.                     case '@':                    /* user@@ */
  674.                     case '<':                    /* user@< */
  675.                     case '$':                    /* user@$ */
  676.                         state = ERROR_STATE ;
  677.                         break ;
  678.                     default:
  679.                         if (!isspace(*cp)) {
  680.                             host = cp ;
  681.                             hostlen++ ;
  682.                             state = IN_HOST ;
  683.                         }
  684.                 }
  685.                 break ;
  686.             case IN_HOST:
  687.                 switch (*cp) {
  688.                     case '\0':
  689.                         state = FINAL_STATE ;        /* found user@host */
  690.                         break ;
  691.                     case '@':
  692.                         state = ERROR_STATE ;        /* user@host@? */
  693.                         break ;
  694.                     case '<':
  695.                         state = LOOK_FOR_FROM ;        /* fromname follows */
  696.                         break ;
  697.                     case '$':
  698.                         state = LOOK_FOR_MSGID ;    /* message id follows */
  699.                         break ;
  700.                     default:
  701.                         if (isspace(*cp))
  702.                             state = AFTER_HOST ;
  703.                         else
  704.                             hostlen++ ;
  705.                 }
  706.                 break ;
  707.             case AFTER_HOST:
  708.                 switch (*cp) {
  709.                     case '\0':
  710.                         state = FINAL_STATE ;        /* user@host */
  711.                         break ;
  712.                     case '@':
  713.                         state = ERROR_STATE ;        /* user@host @ */
  714.                         break ;
  715.                     case '<':
  716.                         state = LOOK_FOR_FROM ;        /* user@host < */
  717.                         break ;
  718.                     case '$':
  719.                         state = LOOK_FOR_MSGID ;    /* user@host $ */
  720.                         break ;
  721.                     default:
  722.                         if (!isspace(*cp))
  723.                             state = ERROR_STATE ;    /* user@host foo */
  724.                 }
  725.                 break ;
  726.             case LOOK_FOR_FROM:
  727.                 switch (*cp) {
  728.                     case '\0':                    /* user@host <? */
  729.                     case '@':                    /* user@host <@ */
  730.                     case '<':                    /* user@host << */
  731.                     case '$':                    /* user@host <$ */
  732.                         state = ERROR_STATE ;
  733.                         break ;
  734.                     default:
  735.                         if (!isspace(*cp)) {
  736.                             from = cp ;
  737.                             fromlen++ ;
  738.                             state = IN_FROM ;
  739.                         }
  740.                 }
  741.                 break ;
  742.             case IN_FROM:
  743.                 switch (*cp) {
  744.                     case '\0':
  745.                         state = FINAL_STATE ;        /* user@host <foo */
  746.                         break ;
  747.                     case '<':
  748.                         state = ERROR_STATE ;        /* user@host <foo< */
  749.                         break ;
  750.                     case '$':
  751.                         state = LOOK_FOR_MSGID ;    /* message id follows */
  752.                         break ;
  753.                     default:
  754.                         if (isspace(*cp))
  755.                             state = AFTER_FROM ;
  756.                         else
  757.                             fromlen++ ;
  758.                 }
  759.                 break ;
  760.             case AFTER_FROM:
  761.                 switch (*cp) {
  762.                     case '\0':
  763.                         state = FINAL_STATE ;        /* user@host <foo */
  764.                         break ;
  765.                     case '@':                        /* user@host <foo @ */
  766.                     case '<':                        /* user@host <foo < */
  767.                         state = ERROR_STATE ;
  768.                         break ;
  769.                     case '$':
  770.                         state = LOOK_FOR_MSGID ;    /* user@host <foo $ */
  771.                         break ;
  772.                     default:
  773.                         if (!isspace(*cp))
  774.                             state = ERROR_STATE ;    /* user@host foo */
  775.                 }
  776.                 break ;
  777.             case LOOK_FOR_MSGID:
  778.                 if (*cp == '\0')
  779.                     state = ERROR_STATE ;            /* msgid = $? */
  780.                 else if (isspace(*cp))
  781.                     state = ERROR_STATE ;            /* user@host <foo $ bar */
  782.                 else {
  783.                     msgid = cp ;
  784.                     msgidlen++ ;
  785.                     state = IN_MSGID ;
  786.                 }
  787.                 break ;
  788.             case IN_MSGID:
  789.                 if (*cp == '\0')
  790.                     state = FINAL_STATE ;
  791.                 else if (isspace(*cp))
  792.                     state = FINAL_STATE ;
  793.                 else
  794.                     msgidlen++ ;
  795.                 break ;
  796.             default:
  797.                 /* what are we doing in this state? */
  798.                 state = ERROR_STATE ;
  799.         }
  800.     }
  801.  
  802.     if (state == ERROR_STATE)
  803.         return -1 ;        /* syntax error */
  804.  
  805.     if ((m->to = malloc(userlen + hostlen + 2)) == NULLCHAR)
  806.         return -1 ;        /* no room for to address */
  807.  
  808.     strncpy(m->to, user, userlen) ;
  809.     m->to[userlen] = '\0' ;
  810.     
  811.     if (hostlen) {
  812.         m->to[userlen] = '@' ;
  813.         strncpy(m->to + userlen + 1, host, hostlen) ;
  814.         m->to[userlen + hostlen + 1] = '\0' ;
  815.     }
  816.  
  817.     if (fromlen) {
  818.         if ((m->tofrom = malloc(fromlen + 1)) == NULLCHAR) {
  819.             free(m->to) ;
  820.             m->to = NULLCHAR ;
  821.             return -1 ;
  822.         }
  823.         strncpy(m->tofrom, from, fromlen) ;
  824.         m->tofrom[fromlen] = '\0' ;
  825.     }
  826.  
  827.     if (msgidlen) {
  828.         if ((m->tomsgid = malloc(msgidlen + 1)) == NULLCHAR) {
  829.             free(m->to) ;
  830.             m->to = NULLCHAR ;
  831.             if (fromlen) {
  832.                 free(m->tofrom) ;
  833.                 m->tofrom = NULLCHAR ;
  834.             }
  835.             return -1 ;
  836.         }
  837.         strncpy(m->tomsgid, msgid, msgidlen) ;
  838.         m->tomsgid[msgidlen] = '\0' ;
  839.     }
  840.     
  841.     return 0 ;
  842. }
  843.  
  844. /* This opens the data file and writes the mail header into it.
  845.  * Returns 0 if OK, and -1 if not.
  846.  */
  847.  
  848. static
  849. mbx_data(m)
  850. struct mbx *m ;
  851. {
  852.     time_t t;
  853.     char *ptime() ;
  854.     extern char hostname[] ;
  855.     extern FILE *tmpfile();
  856.     extern long get_msgid() ;
  857.     
  858.     if ((m->tfile = tmpfile()) == NULLFILE)
  859.         return -1 ;
  860.  
  861.     time(&t) ;
  862.     fprintf(m->tfile,"Date: %s",ptime(&t)) ;
  863.     if (m->tomsgid)
  864.         fprintf(m->tfile, "Message-Id: <%s@%s>\n", m->tomsgid, hostname) ;
  865.     else
  866.         fprintf(m->tfile,"Message-Id: <%ld@%s>\n",get_msgid(),hostname) ;
  867.     fprintf(m->tfile,"From: %s%%%s.bbs@%s\n",
  868.             m->tofrom ? m->tofrom : m->name, m->name, hostname) ;
  869.     fprintf(m->tfile,"To: %s\n",m->to) ;
  870.     fprintf(m->tfile,"Subject: %s\n",m->line) ;
  871.     if (m->stype != ' ')
  872.         fprintf(m->tfile,"X-BBS-Msg-Type: %c\n", m->stype) ;
  873.     fprintf(m->tfile,"\n") ;
  874.     
  875.     return 0 ;
  876. }
  877.  
  878.